﻿//module;
/*
 * @author rayzhang
 * @date 2023/03/30
 * @desc 组件间共享的状态，在这进行管理
 *
 */
// #include "property.hpp"
#include <memory>
#include <QMap>
#include <QObject>
#include <QString>
#include "../router/action_dispatcher.h"
//export module libflow.store;
// 跨组件数据共享以及方便的在非成员函数中使用状态数据(函数式)。
/*export */namespace flow
{
class Store;
using StorePtr = std::shared_ptr<Store>;

class Store : public QObject
{
public:
    explicit Store(QString key, QObject* parent = nullptr)
        : QObject(parent)
        , _key{std::move(key)}
        , _dispatcher(std::make_unique<ActionDispatcher>())
    { }

    // ReSharper disable once CppEnforceOverridingDestructorStyle
    virtual ~Store(){}; // NOLINT

    [[nodiscard]] virtual const QString& key() const { return _key; }

    // actions
    const auto& dispatcher() const { return _dispatcher; }
    // 助手函数
    auto dispatch(const QString& action, ActionDispatcher::PayloadType payload = {}) const { return _dispatcher->dispatch(action, std::move(payload)); }

private:
    QString _key;
    flow::ActionDispatcherPtr _dispatcher;
};

class StoreProvider final
{
    QMap<QString, std::shared_ptr<Store>> _stores;

public:
    static StoreProvider& instance()
    {
        static std::unique_ptr store{std::make_unique<StoreProvider>()};
        return *store;
    }

    bool contains(const QString& key) const { return _stores.contains(key); }
    // 插入
    void insert(const QString& key, StorePtr store) { _stores[key] = std::move(store); }
    // 移除
    virtual void remove(const QString& key)
    {
        if (contains(key)) {
            _stores.remove(key);
        }
    }

    // 获取
    template <typename T>
        requires std::is_base_of_v<Store, T>
    std::shared_ptr<T> get(const QString& key)
    {
        if (contains(key)) {
            return std::dynamic_pointer_cast<T>(_stores[key]);
        }
        return nullptr;
    }
};

template <typename T>
auto useStore(const QString& key)
{
    if (auto& storeProvider = StoreProvider::instance(); !storeProvider.contains(key)) {
        const auto store = std::make_shared<T>(key);
        storeProvider.insert(store->key(), store);
    }
    return StoreProvider::instance().get<T>(key);
}

// store factory
template <typename T>
auto defineStore(const QString& key)
    requires std::is_base_of_v<Store, T>
{
    return [key] {
        return useStore<T>(key).get();
    };
}
} // namespace flow
